home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / shadow-9.tar / shadow-9 / shadow-960129 / port.c < prev    next >
C/C++ Source or Header  |  1995-12-17  |  11KB  |  452 lines

  1. /*
  2.  * Copyright 1989 - 1994, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by John F. Haugh, II
  16.  *      and other contributors.
  17.  * 4. Neither the name of John F. Haugh, II nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY JOHN HAUGH AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL JOHN HAUGH OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <time.h>
  36. #include <sys/types.h>
  37. #include <ctype.h>
  38. #include <errno.h>
  39. #include "defines.h"
  40. #include "port.h"
  41.  
  42. #ifndef    lint
  43. static char rcsid[] = "$Id: port.c,v 1.1 1995/12/16 01:15:45 marekm Exp $";
  44. #endif
  45.  
  46. extern    int    errno;
  47.  
  48. static    FILE    *ports;
  49.  
  50. /*
  51.  * portcmp - compare the name of a port to a /etc/porttime entry
  52.  *
  53.  *    portcmp works like strcmp, except that if the last character
  54.  *    in a failing match is a '*', the match is considered to have
  55.  *    passed.  The "*" match is suppressed whenever the port is "SU",
  56.  *    which is the token the "su" command uses to validate access.
  57.  *    A match returns 0, failure returns non-zero.
  58.  */
  59.  
  60. static int
  61. portcmp (pattern, port)
  62. char    *pattern;
  63. char    *port;
  64. {
  65.     char    *orig = port;
  66.  
  67.     while (*pattern && *pattern == *port)
  68.         pattern++, port++;
  69.  
  70.     if (*pattern == 0 && *port == 0)
  71.         return 0;
  72.     if (orig[0] == 'S' && orig[1] == 'U' && orig[2] == '\0')
  73.         return 1;
  74.  
  75.     return *pattern == '*' ? 0:1;
  76. }
  77.  
  78. /*
  79.  * setportent - open /etc/porttime file or rewind
  80.  *
  81.  *    the /etc/porttime file is rewound if already open, or
  82.  *    opened for reading.
  83.  */
  84.  
  85. void
  86. setportent ()
  87. {
  88.     if (ports)
  89.         rewind (ports);
  90.     else 
  91.         ports = fopen (PORTS, "r");
  92. }
  93.  
  94. /*
  95.  * endportent - close the /etc/porttime file
  96.  *
  97.  *    the /etc/porttime file is closed and the ports variable set
  98.  *    to NULL to indicate that the /etc/porttime file is no longer
  99.  *    open.
  100.  */
  101.  
  102. void
  103. endportent ()
  104. {
  105.     if (ports)
  106.         fclose (ports);
  107.  
  108.     ports = (FILE *) 0;
  109. }
  110.  
  111. /*
  112.  * getportent - read a single entry from /etc/porttime
  113.  *
  114.  *    the next line in /etc/porttime is converted to a (struct port)
  115.  *    and a pointer to a static (struct port) is returned to the
  116.  *    invoker.  NULL is returned on either EOF or error.  errno is
  117.  *    set to EINVAL on error to distinguish the two conditions.
  118.  */
  119.  
  120. struct port *
  121. getportent ()
  122. {
  123.     static    struct    port    port;    /* static struct to point to         */
  124.     static    char    buf[BUFSIZ];    /* some space for stuff              */
  125.     static    char    *ttys[PORT_TTY+1]; /* some pointers to tty names     */
  126.     static    char    *users[PORT_IDS+1]; /* some pointers to user ids     */
  127.     static    struct    pt_time    times[PORT_TIMES+1]; /* time ranges          */
  128.     char    *cp;            /* pointer into line                 */
  129.     int    time;            /* scratch time of day               */
  130.     int    i, j;
  131.     int    saveerr = errno;    /* errno value on entry              */
  132.  
  133.     /*
  134.      * If the ports file is not open, open the file.  Do not rewind
  135.      * since we want to search from the beginning each time.
  136.      */
  137.  
  138.     if (! ports)
  139.         setportent ();
  140.  
  141.     if (! ports) {
  142.         errno = saveerr;
  143.         return 0;
  144.     }
  145.  
  146.     /*
  147.      * Common point for beginning a new line -
  148.      *
  149.      *    - read a line, and NUL terminate
  150.      *    - skip lines which begin with '#'
  151.      *    - parse off the tty names
  152.      *    - parse off a list of user names
  153.      *    - parse off a list of days and times
  154.      */
  155.  
  156. again:
  157.  
  158.     /*
  159.      * Get the next line and remove the last character, which
  160.      * is a '\n'.  Lines which begin with '#' are all ignored.
  161.      */
  162.  
  163.     if (fgets (buf, BUFSIZ, ports) == 0) {
  164.         errno = saveerr;
  165.         return 0;
  166.     }
  167.     if (buf[0] == '#')
  168.         goto again;
  169.  
  170.     /*
  171.      * Get the name of the TTY device.  It is the first colon
  172.      * separated field, and is the name of the TTY with no
  173.      * leading "/dev".  The entry '*' is used to specify all
  174.      * TTY devices.
  175.      */
  176.  
  177.     buf[strlen (buf) - 1] = 0;
  178.  
  179.     port.pt_names = ttys;
  180.     for (cp = buf, j = 0;j < PORT_TTY;j++) {
  181.         port.pt_names[j] = cp;
  182.         while (*cp && *cp != ':' && *cp != ',')
  183.             cp++;
  184.  
  185.         if (! *cp)
  186.             goto again;    /* line format error */
  187.  
  188.         if (*cp == ':')        /* end of tty name list */
  189.             break;
  190.  
  191.         if (*cp == ',')        /* end of current tty name */
  192.             *cp++ = '\0';
  193.     }
  194.     *cp++ = 0;
  195.     port.pt_names[j + 1] = (char *) 0;
  196.  
  197.     /*
  198.      * Get the list of user names.  It is the second colon
  199.      * separated field, and is a comma separated list of user
  200.      * names.  The entry '*' is used to specify all usernames.
  201.      * The last entry in the list is a (char *) 0 pointer.
  202.      */
  203.  
  204.     if (*cp != ':') {
  205.         port.pt_users = users;
  206.         port.pt_users[0] = cp;
  207.  
  208.         for (j = 1;*cp != ':';cp++) {
  209.             if (*cp == ',' && j < PORT_IDS) {
  210.                 *cp++ = 0;
  211.                 port.pt_users[j++] = cp;
  212.             }
  213.         }
  214.         port.pt_users[j] = 0;
  215.     } else
  216.         port.pt_users = 0;
  217.  
  218.     if (*cp != ':')
  219.         goto again;
  220.  
  221.     *cp++ = 0;
  222.  
  223.     /*
  224.      * Get the list of valid times.  The times field is the third
  225.      * colon separated field and is a list of days of the week and
  226.      * times during which this port may be used by this user.  The
  227.      * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'.
  228.      *
  229.      * In addition, the value 'Al' represents all 7 days, and 'Wk'
  230.      * represents the 5 weekdays.
  231.      *
  232.      * Times are given as HHMM-HHMM.  The ending time may be before
  233.      * the starting time.  Days are presumed to wrap at 0000.
  234.      */
  235.  
  236.     if (*cp == '\0') {
  237.         port.pt_times = 0;
  238.         return &port;
  239.     }
  240.  
  241.     port.pt_times = times;
  242.  
  243.     /*
  244.      * Get the next comma separated entry
  245.      */
  246.  
  247.     for (j = 0;*cp && j < PORT_TIMES;j++) {
  248.  
  249.         /*
  250.          * Start off with no days of the week
  251.          */
  252.  
  253.         port.pt_times[j].t_days = 0;
  254.  
  255.         /*
  256.          * Check each two letter sequence to see if it is
  257.          * one of the abbreviations for the days of the
  258.          * week or the other two values.
  259.          */
  260.  
  261.         for (i = 0;cp[i] && cp[i + 1] && isalpha (cp[i]);i += 2) {
  262.             switch ((cp[i] << 8) | (cp[i + 1])) {
  263.                 case ('S' << 8) | 'u':
  264.                     port.pt_times[j].t_days |= 01;
  265.                     break;
  266.                 case ('M' << 8) | 'o':
  267.                     port.pt_times[j].t_days |= 02;
  268.                     break;
  269.                 case ('T' << 8) | 'u':
  270.                     port.pt_times[j].t_days |= 04;
  271.                     break;
  272.                 case ('W' << 8) | 'e':
  273.                     port.pt_times[j].t_days |= 010;
  274.                     break;
  275.                 case ('T' << 8) | 'h':
  276.                     port.pt_times[j].t_days |= 020;
  277.                     break;
  278.                 case ('F' << 8) | 'r':
  279.                     port.pt_times[j].t_days |= 040;
  280.                     break;
  281.                 case ('S' << 8) | 'a':
  282.                     port.pt_times[j].t_days |= 0100;
  283.                     break;
  284.                 case ('W' << 8) | 'k':
  285.                     port.pt_times[j].t_days |= 076;
  286.                     break;
  287.                 case ('A' << 8) | 'l':
  288.                     port.pt_times[j].t_days |= 0177;
  289.                     break;
  290.                 default:
  291.                     errno = EINVAL;
  292.                     return 0;
  293.             }
  294.         }
  295.  
  296.         /*
  297.          * The default is 'Al' if no days were seen.
  298.          */
  299.  
  300.         if (i == 0)
  301.             port.pt_times[j].t_days = 0177;
  302.  
  303.         /*
  304.          * The start and end times are separated from each
  305.          * other by a '-'.  The times are four digit numbers
  306.          * representing the times of day.
  307.          */
  308.  
  309.         for (time = 0;cp[i] && isdigit (cp[i]);i++)
  310.             time = time * 10 + cp[i] - '0';
  311.  
  312.         if (cp[i] != '-' || time > 2400 || time % 100 > 59)
  313.             goto again;
  314.         port.pt_times[j].t_start = time;
  315.         cp = cp + i + 1;
  316.  
  317.         for (time = i = 0;cp[i] && isdigit (cp[i]);i++)
  318.             time = time * 10 + cp[i] - '0';
  319.  
  320.         if ((cp[i] != ',' && cp[i]) || time > 2400 || time % 100 > 59)
  321.             goto again;
  322.  
  323.         port.pt_times[j].t_end = time;
  324.         cp = cp + i + 1;
  325.     }
  326.  
  327.     /*
  328.      * The end of the list is indicated by a pair of -1's for the
  329.      * start and end times.
  330.      */
  331.  
  332.     port.pt_times[j].t_start = port.pt_times[j].t_end = -1;
  333.  
  334.     return &port;
  335. }
  336.  
  337. /*
  338.  * getttyuser - get ports information for user and tty
  339.  *
  340.  *    getttyuser() searches the ports file for an entry with a TTY
  341.  *    and user field both of which match the supplied TTY and
  342.  *    user name.  The file is searched from the beginning, so the
  343.  *    entries are treated as an ordered list.
  344.  */
  345.  
  346. struct port *
  347. getttyuser (tty, user)
  348. char    *tty;
  349. char    *user;
  350. {
  351.     int    i, j;
  352.     struct    port    *port;
  353.  
  354.     setportent ();
  355.  
  356.     while ((port = getportent ())) {
  357.         if (port->pt_names == 0 || port->pt_users == 0)
  358.             continue;
  359.  
  360.         for (i = 0;port->pt_names[i];i++)
  361.             if (portcmp (port->pt_names[i], tty) == 0)
  362.                 break;
  363.  
  364.         if (port->pt_names[i] == 0)
  365.             continue;
  366.  
  367.         for (j = 0;port->pt_users[j];j++)
  368.             if (strcmp (user, port->pt_users[j]) == 0 ||
  369.                     strcmp (port->pt_users[j], "*") == 0)
  370.                 break;
  371.  
  372.         if (port->pt_users[j] != 0)
  373.             break;
  374.     }
  375.     endportent ();
  376.     return port;
  377. }
  378.  
  379. /*
  380.  * isttytime - tell if a given user may login at a particular time
  381.  *
  382.  *    isttytime searches the ports file for an entry which matches
  383.  *    the user name and TTY given.
  384.  */
  385.  
  386. int
  387. isttytime (id, port, clock)
  388. char    *id;
  389. char    *port;
  390. long    clock;
  391. {
  392.     int    i;
  393.     int    time;
  394.     struct    port    *pp;
  395.     struct    tm    *tm,
  396.             *localtime();
  397.  
  398.     /*
  399.      * Try to find a matching entry for this user.  Default to
  400.      * letting the user in - there are pleny of ways to have an
  401.      * entry to match all users.
  402.      */
  403.  
  404.     if (! (pp = getttyuser (port, id)))
  405.         return 1;
  406.  
  407.     /*
  408.      * The entry is there, but has no time entries - don't
  409.      * ever let them login.
  410.      */
  411.  
  412.     if (pp->pt_times == 0)
  413.         return 0;
  414.  
  415.     /*
  416.      * The current time is converted to HHMM format for
  417.      * comparision against the time values in the TTY entry.
  418.      */
  419.  
  420.     tm = localtime (&clock);
  421.     time = tm->tm_hour * 100 + tm->tm_min;
  422.  
  423.     /*
  424.      * Each time entry is compared against the current
  425.      * time.  For entries with the start after the end time,
  426.      * the comparision is made so that the time is between
  427.      * midnight and either the start or end time.
  428.      */
  429.  
  430.     for (i = 0;pp->pt_times[i].t_start != -1;i++) {
  431.         if (! (pp->pt_times[i].t_days & PORT_DAY(tm->tm_wday)))
  432.             continue;
  433.  
  434.         if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) {
  435.             if (time >= pp->pt_times[i].t_start &&
  436.                     time <= pp->pt_times[i].t_end)
  437.                 return 1;
  438.         } else {
  439.             if (time >= pp->pt_times[i].t_start ||
  440.                     time <= pp->pt_times[i].t_end)
  441.                 return 1;
  442.         }
  443.     }
  444.  
  445.     /*
  446.      * No matching time entry was found, user shouldn't
  447.      * be let in right now.
  448.      */
  449.  
  450.     return 0;
  451. }
  452.